HTTP, REST & ASP.NET

📄 REST

Определение: Это некоторый набор правил по созданию API


📄 ASP.NET Core

ASP.NET Core кроссплатформенный в отличие от ASP.NET

⚙ Способы инициализации хоста

1. Инициализация сразу веб приложения

var builder = WebApplication.CreateBuilder(args) 

Пример:

public static void Main(string[] args)
{
    var builder = WebApplication.CreateBuilder(args);

    // Add services to the container.

    builder.Services.AddControllers();
    // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
    builder.Services.AddEndpointsApiExplorer();
    builder.Services.AddSwaggerGen();

    var app = builder.Build();

    // Configure the HTTP request pipeline.
    if (app.Environment.IsDevelopment())
    {
        app.UseSwagger();
        app.UseSwaggerUI();
    }

    app.UseAuthorization();


    app.MapControllers();

    app.Run();
}

Данный способ инициализации инитиализирует службы не только DI, но и нужные для создания Web приложений

2. Инициализация обычного приложения с включенным DI и логированием.

var builder = Host.CreateDefaultBuilder(args);

⚙ Взаимодейсвтие с сервисами

Добавление Startup.cs

Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });

Startup должен содержать два метода:

  1. Configure(IApplicationBuilder app, IHostEnvironment env) для регистрации MiddleWare
  2. ConfigureServices(IServiceCollection services) для регистрации новых сервисов

Существуют следующие способы добавить новый сервис:

  1. services.AddHostedService(); Для регистрации фоновой службы.
  2. services.AddSingleton() Для регистрации сервиса в DI в одном экземпляре.
  3. services.AddTransient() Для регистрации сервиса в DI .При каждом обращении к сервису создается новый объект сервиса. В течение одного запроса может быть несколько обращений к сервису, соответственно при каждом обращении будет создаваться новый объект. Подобная модель жизненного цикла наиболее подходит для легковесных сервисов, которые не хранят данных о состоянии
  4. services.Scoped() Для каждого запроса создается свой объект сервиса. То есть если в течение одного запроса есть несколько обращений к одному сервису, то при всех этих обращениях будет использоваться один и тот же объект сервиса.

⚙ Middleware

  • Время жизни Middleware - Singltone
  • Также существуют Middleware методы MapWhen() и UseWhen() которые принимают дополнительный булевый делагат

⚙ Configuration и Environments

Переменные которые отвечают за понимание ASP.NET Core в каком окружении оно запущено может происходить через одну из двух переменных:

  • DOTNET_ENVIRONMENT
  • ASPNETCORE_ENVIRONMENT

Локально её переопределить можно через launchSettings.json

На этапе запуска приложение преобразует все источники конфигураций в единый словарь

Поставщики конфигурации это специальные классы, которые могут загружать конфигурацию из различных источников.
виды источников конфигурации:

  • Файлы параметров, например appsettings.json
  • Переменные среды
  • Аргументы командной строки
  • Справочные материалы, например .xml
  • Пользовательские секреты
  • Объекты .NET в памяти

Для создания своего кастомого поставщика нужно реализовать интерфейс IConfigurationProvider

Далее к словарю конфигураций можно обращаться через класс IConfiguration

Чтобы привести её к определенному классу прмиеняется метод

Services.Configure(Configuration)

ASP.NET Core поддерживает перезагрузку конфигураций на лету, но её нужно отдельно подключить


⚙ Контроллеры и Экшены

Контроллеры и экшены это уже часть другого фреймворка ASP.NET Core MVC

  • Роутинг на основе атрибутов
app.UseRouting();

app.UseEndpoints(endpoints ⇒ endpoints.MapControllers());
[Route("some/path")]
public class SomeController : ControllerBase
{
	[HttpGet]
	public async Task<List<ResponseClass>> GetResponseAsync(){
		// Some code
	}
}

Также можно регистрировать эндпоинты на основе соглашений

Untitled 3.png

  • При создании маршрута можно накладывать ограничения на передаваемые параметры, например:
[Route("users/{id:int(min(1))}")]
  • Также в маршруте можно использовать плейсхолдеры
    1. Action
    2. Area
    3. Controller
    4. Handler
    5. Page
    Пример:
[Route("[controller]/[action]")]
  • Model Binding
    1. [FromQuery] - строки запроса
    2. [FromRoute] - данные текущего роута
    3. [FromForm] - Поля формы
    4. [FromBody] - тело запроса
    5. [FromHeader] - заголовки запроса

⚙ Action Filters

Типы:

  1. Authorization - выполняются раньше всех, проверяют имеет ли пользователь доступ
  2. Resource - выполняются когда нужно выйти из пайпалайна не совершая обработку, например в случае кэширования.
  3. Action - выполняются после model binding и позволяют взаимодействовать с параметрами. Например в случае валидации.
  4. Exception - для обработки исключений
  5. Result - выполняют код непосредственно после выполнения экшенов в контроллере, отличие от обычного Action в том что вы не можете переопределять результат который вернут клиенту, но при этом вы точно знаете что именно вернется клиенту

Untitled 1 2.png

Также, в случае если вам важен порядок выполнения фильтров то можно его задать через парметр атрибута или реализовывать более низкоуровнего, реализовав интерфейсы и подключив их к контроллеру через

services.AddControllers(x => 
{
	x.Filters.AddService<SomeFilter>();
})

Также, если прям очень надо, можно делать так:

[MiddlewareFilter(typeof(SomeMiddleware))]